#include "tcp_sender.hh"

#include "tcp_config.hh"
#include "util.hh"

#include <random>
#include <iostream>
#include <stdio.h>
// Dummy implementation of a TCP sender

// For Lab 3, please replace with a real implementation that passes the
// automated checks run by `make check_lab3`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

//! \param[in] capacity the capacity of the outgoing byte stream
//! \param[in] retx_timeout the initial amount of time to wait before retransmitting the oldest outstanding segment
//! \param[in] fixed_isn the Initial Sequence Number to use, if set (otherwise uses a random ISN)
TCPSender::TCPSender(const size_t capacity, const uint16_t retx_timeout, const std::optional<WrappingInt32> fixed_isn)
    : _isn(fixed_isn.value_or(WrappingInt32{random_device()()}))
    , _initial_retransmission_timeout{retx_timeout}
    , _stream(capacity)
    , _retransmission_timer(retx_timeout, UINT64_MAX){
}

size_t TCPSender::bytes_in_flight() const {
    return _bytes_in_flight;
}

void TCPSender::fill_window() {
    if(_fin_sent)
        return;
    if(_next_seqno && !_stream.input_ended() && _stream.buffer_empty())
        return;

//    if(_stream.input_ended())
//        cerr << "\nstart fin\n";
    size_t &&bufsize = _stream.buffer_size();
    bool need_syn = !_next_seqno;
//    if(_stream.input_ended())
//        cerr << "\nfin condition: !_fin_sent=" << !_fin_sent << ", bufsize=" << bufsize << ", TCPConfig::MAX_PAYLOAD_SIZE="
//             << TCPConfig::MAX_PAYLOAD_SIZE << ", win_size=" << _win_size << "\n";
    bool need_fin = !_fin_sent && _stream.input_ended() && bufsize <= TCPConfig::MAX_PAYLOAD_SIZE;
//    if(need_fin)
//        cerr << "prepare fin\n";
    // 不能发送无数据，且无syn，无fin的。这只能用send_empty_segment()
//    cerr << (_stream.buffer_empty() && !need_fin && !need_syn) << "\n";
    if(_stream.buffer_empty() && !need_fin && !need_syn)
        return;

    /* 到这步，一定有占序号的字节可发 */

    uint16_t realWinSize = _win_size;
//    if(need_fin)
//        cerr << realWinSize << endl;
    if(!realWinSize) {
        //send_empty_segment();
        //realWinSize = 1;
        return;
    }
    // 1、有syn时，必须发，fin可能就不够发，要把need_fin设为false
    // 2、若要发fin，必须把buf全部发出去，并且加上fin，如果realWinSize不够的话，就不能发fin
//    if(need_fin)
//        cerr << (realWinSize < need_fin + need_syn || bufsize + need_syn + need_fin > realWinSize) << endl;
    if(realWinSize < need_fin + need_syn || bufsize + need_syn + need_fin > realWinSize)
        need_fin = false;

//    cerr << (need_fin? "need_fin" : "don't need fin") << endl;
    uint16_t &&payload_size = min(min(bufsize, static_cast<size_t>(realWinSize - need_syn - need_fin))
                                , TCPConfig::MAX_PAYLOAD_SIZE);

/* _win_size为0时，当作1 */
//    uint16_t realWinSize = _win_size? _win_size : 1;
//    cerr << realWinSize << endl;
////    if(!realWinSize)
////        return;
//    // 1、有syn时，必须发，fin可能就不够发，要把need_fin设为false
//    // 2、若要发fin，必须把buf全部发出去，并且加上fin，如果realWinSize不够的话，就不能发fin
//    cerr << (realWinSize - need_syn < need_fin || _stream.buffer_size() + need_syn + need_fin > realWinSize) << endl;
//    if(realWinSize - need_syn < need_fin || _stream.buffer_size() + need_syn + need_fin > realWinSize)
//        need_fin = false;
//
//    cerr << "need_fin = " << need_fin << endl;
//    uint16_t &&payload_size = min(min(_stream.buffer_size(), static_cast<size_t>(realWinSize - need_syn - need_fin))
//        , TCPConfig::MAX_PAYLOAD_SIZE);

/* syn不占用win */
//    uint16_t realWinSize = _win_size + need_syn;
//    cerr << realWinSize << endl;
//    if(!realWinSize)
//        return;
//    // 1、有syn时，必须发，fin可能就不够发，要把need_fin设为false
//    // 2、若要发fin，必须把buf全部发出去，并且加上fin，如果realWinSize不够的话，就不能发fin
//    cerr << (_win_size < need_fin || _stream.buffer_size() + need_fin > _win_size) << endl;
//    if(_win_size < need_fin || _stream.buffer_size() + need_fin > _win_size)
//        need_fin = false;
//
//    cerr << "need_fin = " << need_fin << endl;
//    uint16_t &&payload_size = min(min(_stream.buffer_size(), static_cast<size_t>(realWinSize - need_syn - need_fin))
//        , TCPConfig::MAX_PAYLOAD_SIZE);

    size_t &&len = payload_size + need_syn + need_fin;

//    if(need_fin)
//        cerr << "send fin\n";
    TCPSegment segment;
    TCPHeader &header = segment.header();
    header.seqno = wrap(_next_seqno, _isn);
    //header.ack = false;
    header.syn = need_syn;
    header.fin = need_fin;

    string &&data = _stream.read(payload_size);
    segment.payload() = Buffer(move(data));
    _segments_out.emplace(segment);

    if(_seg_in_flight_pq.empty())
        _retransmission_timer.start();
    _seg_in_flight_pq.emplace(_next_seqno + len - 1, segment);
    _bytes_in_flight += len;
    _next_seqno += len;
    _fin_sent = need_fin;
    _win_size -= len;

//    cerr << "\n-- after fill, sender's stream bufsize is " << _stream.buffer_size() << ", winsize is " << _win_size << endl;

    if(_win_size)
        fill_window();

}

//! \param ackno The remote receiver's ackno (acknowledgment number)
//! \param window_size The remote receiver's advertised window size
void TCPSender::ack_received(const WrappingInt32 ackno, const uint16_t window_size) {
    //cerr << "\n-- peer's winsize is " << window_size << endl;
    //_next_seqno = unwrap(ackno, _isn, _next_seqno);
    uint64_t &&abs_seqno = unwrap(ackno, _isn, _next_seqno);
    if(abs_seqno > _next_seqno)
        return;
    _newest_abs_ackno = abs_seqno;
    // 算出实际有效窗口；
    // 如果窗口为0，且abs_seqno == _next_seqno，则视作1来看待
    uint64_t &&right = window_size? abs_seqno + window_size - 1 : abs_seqno - 1;
    _origin_win_size = uint16_t(right < _next_seqno? 0 : right - _next_seqno + 1);
    _win_size = max(uint16_t(abs_seqno == _next_seqno), _origin_win_size);
    //cerr << "\n-- _win_size updated to " << _win_size << endl;
    // 无new data
    if(abs_seqno <= _seg_in_flight_pq.top()._last_abs_seqno)
        return;

    // 有new data
    while(!_seg_in_flight_pq.empty() && abs_seqno > _seg_in_flight_pq.top()._last_abs_seqno){
        _bytes_in_flight -= _seg_in_flight_pq.top()._segment.length_in_sequence_space();
        _seg_in_flight_pq.pop();
    }
    if(!_seg_in_flight_pq.empty()){
        resetTimer();
    }else{
        stopTimer();
    }
}

//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
void TCPSender::tick(const uint64_t ms_since_last_tick) {
    _retransmission_timer.addCur(ms_since_last_tick);
    if(_retransmission_timer.isExpired()){
        auto &seg_in_flight = _seg_in_flight_pq.top();
//        cerr << "\n-- retran seg, header is " << seg_in_flight._segment.header().to_string() << endl;
        _segments_out.emplace(seg_in_flight._segment);
        if(_origin_win_size || _bytes_in_flight == _next_seqno) {
            _retransmission_timer.setRtoAndExpireT(_retransmission_timer.getRto() << 1);
            ++_consecutive_retransmissions;
        }else{
            _retransmission_timer.start();
        }
    }
}

unsigned int TCPSender::consecutive_retransmissions() const {
    return _consecutive_retransmissions;
}

void TCPSender::send_empty_segment() {
//    if(_fin_sent)
//        return;
    TCPSegment segment;
    segment.header().seqno = wrap(_newest_abs_ackno, _isn);
    //cerr << "\n-- Send EMPTY: seqno is " << header.seqno << " _newest_abs_ackno is " << _newest_abs_ackno << ", _isn is " << _isn << endl;

//    InternetChecksum check(0);
//    check.add(header.serialize());
//    header.cksum = check.value();
//    string &&str_content = header.serialize();
//    cerr << "\n-- Send EMPTY: after serialize, header is " << *reinterpret_cast<uint32_t*>(&str_content[4]) << endl;

//    Buffer content(move(str_content));
//
//    auto err = segment.parse(content);
//    cerr << "\n-- Send EMPTY: after parse, error is " << static_cast<uint32_t>(err) << endl;
//    cerr << "\n-- Send EMPTY: after parse, seqno is " << segment.header().seqno << endl;
    _segments_out.emplace(segment);
//    cerr << "\n-- Send EMPTY: after emplace, seqno is " << _segments_out.back().header().seqno << endl;
}